﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using YasharEl.Infrastructure.ApplicationModel.Bootstrap.Extensibility;
using YasharEl.Infrastructure.ApplicationModel.Bootstrap.Configuration;
using YasharEl.Infrastructure.ApplicationModel.Modularity.Configuration;
using System.Configuration;
using YasharEl.Infrastructure.ApplicationModel.Modularity;
using YasharEl.Infrastructure.ObjectFactory;

namespace YasharEl.Infrastructure.ApplicationModel.Bootstrap.Extensions
{
    public class ApplicationModularityConfigurationBootstrapperExtension : InfrastructureComponentBootstrappingExtension,
            ILoadConfigurationSection, IConsumeConfigurationSection
    {
        public ModularityConfig ModularityConfigSection { get; private set; }

        public ConfigurationSection GetSection(string sectionName)
        {
            return ModularityConfig.Instance;
        }

        public void Apply(ConfigurationSection section)
        {
            ModularityConfigSection = section as ModularityConfig;
        }

        public override string Describe()
        {
            return "Extension which init and configure registered modules from config file.Each module contains separated config file.";
        }

        public override void Configure()
        {
            base.Configure();

            if (ModularityConfigSection != null && ModularityConfigSection.Modules != null)
            {
                foreach (ModuleConfig moduleConfig in ModularityConfigSection.Modules)
                {
                    Logger.Info("Initializing module {0} ...", moduleConfig.ModuleName);

                    Container.DependencyRegistrar.Register(
                        typeof(IModule),
                        moduleConfig.ModuleType,
                        moduleConfig.ModuleName,
                        true
                    );
                    IModule module = Container.DependencyResolver.Resolve<IModule>(moduleConfig.ModuleName);
                    BaseDependencyContainer moduleContainer =
                        (BaseDependencyContainer)Container.CreateChildContainer(moduleConfig.ModuleName);

                    Logger.Info("Module {0} child container created...", moduleConfig.ModuleName);

                    module.Initialize(
                        moduleContainer,
                        moduleConfig.ModuleName,
                        moduleConfig.SettingsFile
                    );

                    IDependencyContainer foundChildContainer = Container.FindChildContainer(moduleConfig.ModuleName);
                    if (foundChildContainer == null)
                    {
                        throw new InvalidSystemConfigurationException(string.Format("Module child container with name {0} could not be resolved from parent container.", moduleConfig.ModuleName));
                    }

                    if (foundChildContainer != moduleContainer)
                    {
                        throw new InvalidSystemConfigurationException(string.Format("Container references to invalid child container[{0}].", moduleConfig.ModuleName));
                    }

                    Logger.Info("{0} module successfully initialized.", moduleConfig.ModuleName);
                }
            }
            else
            {
                Logger.Warn("There is no modules to configure.");
            }
        }

        public override void Start()
        {
            base.Start();

            if (ModularityConfigSection != null && ModularityConfigSection.Modules != null)
            {
                foreach (ModuleConfig moduleConfig in ModularityConfigSection.Modules)
                {
                    Logger.Info("Running module {0} ...", moduleConfig.ModuleName);

                    IModule module = Container.DependencyResolver.Resolve<IModule>(moduleConfig.ModuleName);
                    module.Run();

                    Logger.Info("{0} module successfully run.", moduleConfig.ModuleName);
                }
            }
        }

        public override void Shutdown()
        {
            base.Shutdown();

            if (ModularityConfigSection != null && ModularityConfigSection.Modules != null)
            {
                foreach (ModuleConfig moduleConfig in ModularityConfigSection.Modules)
                {
                    Logger.Info("Shutting down module {0} ...", moduleConfig.ModuleName);

                    IModule module = Container.DependencyResolver.Resolve<IModule>(moduleConfig.ModuleName);
                    module.Shutdown();

                    Logger.Info("{0} module successfully shutdown.", moduleConfig.ModuleName);
                }
            }
        }

        public override void Ready()
        {
            base.Ready();
        }
    }
}
